//
//  EmoticonPackage.swift
//  EmotionKeyBard
//
//  Created by 庄猛 on 17/1/12.
//  Copyright © 2017年 BeiSheng. All rights reserved.
//

import UIKit

class EmoticonPackage: NSObject {
    
    /// 单例
    static let shareInstance: EmoticonPackage = EmoticonPackage()
    
    /// 当前组文件夹名称
    var id: String?

    /// 当前组的名称
    var group_name_cn: String?

    /// 当前组所有的表情模型
    var emoticons: [EmoticonFace]?

    //swift中的kvc赋值
    init(dic:[String :AnyObject]) {
        super.init()
        setValuesForKeys(dic)
    }

    override init() {
     super.init()

    }

    //kvc赋值异常处理
    override func setValue(_ value: Any?, forUndefinedKey key: String) {

    }


    //在swift中想要打印对象要以下重写属性
    override var description: String{
        let keys = ["id","group_name_cn","emoticons"]
        let dic = dictionaryWithValues(forKeys: keys)
        return "\(dic)"
    }



    /**
     加载所有组表情
     */
    class func loadPackages() -> [EmoticonPackage]? {

        // 1.获取emoticons.plist路径
        guard let path = Bundle.main.path(forResource: "emoticons.plist", ofType: nil, inDirectory: "Emoticons.bundle") else {
            return nil
        }



        // 2.根据路径加载字典
        guard let dict = NSDictionary(contentsOfFile: path) else {
            return nil
        }

        // 3.取出所有组数据
        guard let array = dict["packages"] as? [[String: AnyObject]] else {
            return nil
        }

        // 4.遍历数组, 取出每一组的数据
        var models = [EmoticonPackage]()
        //添加最近表情组
        let package = EmoticonPackage()
        package.emoticons = [EmoticonFace]()
        package.appendEmptyEmotion()
        models.append(package)


        for dict in array {
            // 4.1根据字典创建对应组的模型
            let package = EmoticonPackage(dic: dict)
            package.loadEmoticons()
            package.appendEmptyEmotion()
            models.append(package)
        }
        return models
    }


    func addFavoriteEmoticon(emoticon: EmoticonFace) {
        /*
         规则:
         1.最近组永远只能有21个表情, 添加一个必须删除一个
         2.使用次数越多, 那么越排在前面
         3.被添加的表情不能重复
         */

        emoticon.count += 1

        // 0.删除一个按钮
        emoticons?.removeLast()

        // 1.判断当前表情是否已经添加过了
        if !emoticons!.contains(emoticon) {
            // 当前表情没有添加过
            // 1.1删除一个表情
            emoticons?.removeLast()

            // 1.2添加一个表情
            emoticons?.append(emoticon)
        }

        // 2.排序
        emoticons?.sort(by: { (objc1, objc2) -> Bool in
            return objc1.count > objc2.count

        })



        // 3.添加删除按钮
        emoticons?.append(EmoticonFace(isRemoveBtn: true))
    }
    
    
    
    
    
    
    /**
     根据指定字符串, 生成带表情图片的属性字符串
     
     - parameter str: 指定字符串
     
     - returns: 带表情图片的属性字符串
     */
    func attributedString(str: String, font: UIFont) -> NSAttributedString? {
        // 1.编写正则表达式规则
        let pattern = "\\[\\w+\\]"
        
        // 2.根据规则创建正则对象
        guard let regex = try? NSRegularExpression(pattern: pattern, options: NSRegularExpression.Options(rawValue: 0)) else {
            return nil
        }
        // 3.利用正则对象取出结果
        let array = regex.matches(in: str, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, str.characters.count))
        
        // 根据原有字符串生成属性字符串
        let strM = NSMutableAttributedString(string: str)
        
        strM.addAttribute(NSFontAttributeName, value: font, range: NSMakeRange(0, str.characters.count))
        
        //        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init];
        
        let paragr = NSMutableParagraphStyle.init()
        
        paragr.firstLineHeadIndent = 10;
        
        paragr.lineSpacing = 5;
        
        strM.addAttribute(NSParagraphStyleAttributeName, value: paragr, range: NSMakeRange(0, str.characters.count))

        
        // 4.遍历结果集数组, 取出结果
        //        for result in array {
        var index = array.count // 5
        while index > 0 {
            index -= 1  // 4 3 2 1 0
            let result = array[index]
            // 4.1截取表情字符串
            let temp = (str as NSString).substring(with: result.range)
            
            // 4.2根据表情字符串查找表情
            guard let emoticon = findEmoticon(str: temp) else {
                continue
            }
            
            // 4.3利用表情模型创建属性字符串
            
            
            // 1.创建一个附件
            let attachment = EmoticonAttachment()
            attachment.image = UIImage(contentsOfFile: emoticon.imagePath!)
            attachment.chs = emoticon.chs
            // 获取文字的高度
            let height = font.lineHeight
            attachment.bounds = CGRect(x: 0, y: -4, width: height, height: height)
            
            // 2.根据附件创建一个属性字符串
            let attrStr = NSAttributedString(attachment: attachment)

            
            // 4.4利用表情属性字符串替换普通表情字符串
            /*
             {3,5}     {11,4}
             123[好爱哦]456[哈哈]456789
             
             从前往后
             {7,4}
             123😍456[哈哈]😄89
             
             从后往前
             123😍456😄456789
             */
            strM.replaceCharacters(in: result.range, with: attrStr)
        }
        
        // 5.返回结果
        return strM
    }
    
    // MAKR: - 内部控制方法
    /**
     根据字符串查找表情模型
     
     - parameter str: 指定字符串
     
     - returns: 表情模型
     */
    private func findEmoticon(str: String) -> EmoticonFace? {
        // 定义遍历记录结果
        var emoticon: EmoticonFace?
        
        // 1.遍历所有组
        for package in EmoticonPackage.loadPackages()! {
            
            // 最近
            // 2.从当前组中遍历所有表情模型
            emoticon = package.emoticons?.filter({ (e) -> Bool in
                return e.chs == str
            }).last
            
            // 3.判断是否找到了
            if emoticon != nil {
                break
            }
        }
        
        return emoticon
    }





    // MAKR: - 内部控制方法
    /**
     加载当前组所有的表情
     */
    private func loadEmoticons() {
        // 1.生成当前组表情info.plist的路径

        guard let path = Bundle.main.path(forResource: id!, ofType: nil, inDirectory: "Emoticons.bundle") else {
            return
        }

        let filePath = path + "/" + "info.plist"
        // 2.加载当前组的字典
        guard let dict = NSDictionary(contentsOfFile: filePath) else {
            return
        }

        // 3.取出当前组的名称
        group_name_cn = dict["group_name_cn"] as? String

        // 4.加载当前组表情
        guard let array = dict["emoticons"] as? [[String: AnyObject]] else {
            return
        }

        // 5.遍历数组, 取出每个表情
        var models = [EmoticonFace]()

        var index = 0

        for dict in array {

            if index == 20{
                // 追加一个删除按钮
                models.append(EmoticonFace(isRemoveBtn: true))
                index = 0
            }

            let emoticon = EmoticonFace(dic: dict)
            emoticon.id = id
            models.append(emoticon)
            index += 1
        }
        emoticons = models
    }


    private func appendEmptyEmotion(){

        // 1.获取当前组除以21之后的余数
        let count =  emoticons!.count % 21

        // 2.缺几个补几个
        for _ in count..<20 {
            emoticons?.append(EmoticonFace(isRemoveBtn: false))
        }

        // 3.追加一个删除按钮
        emoticons?.append(EmoticonFace(isRemoveBtn: true))
    }




    }






class EmoticonFace: NSObject {

    var isRemoveButton = false

    var count = 0


    /// 当前表情对应的文件夹名称
    var id: String?

    /// 当前表情对应的字符串
    var chs: String?

    /// 当前表情对应的图片
    var png: String?

    var imagePath: String? {
        // 生成当前表情图片的绝对路径
        // 1.生成当前组表情info.plist的路径

        guard let tempId = id else {

            return nil
        }

        guard let path = Bundle.main.path(forResource: tempId, ofType: nil, inDirectory: "Emoticons.bundle") else {
            return nil
        }
        return path + "/" + (png ?? "")
    }

    /// Emoji表情对应的字符串
    var code: String?

    /// Emoji表情处理之后的字符串
    var emoticonStr: String? {

        // 1.创建一个扫描器
        let scanner = Scanner(string: code ?? "")
        // 2.利用扫描器从字符串中扫描出十六进制数
        var result: UInt32 = 0
        scanner.scanHexInt32(&result)
        // 3.利用扫描出来的结果创建一个字符/字符串
        guard let scalar = UnicodeScalar(result) else {
            return nil
        }

        let ch = Character(scalar)
        // 4.显示字符/ 字符串
        return "\(ch)"
    }

    //swift中的kvc赋值
    init(dic:[String :AnyObject]) {
        super.init()
        setValuesForKeys(dic)
    }

    init(isRemoveBtn: Bool) {

        isRemoveButton = isRemoveBtn
    }

    //kvc赋值异常处理
    override func setValue(_ value: Any?, forUndefinedKey key: String) {

    }


    //在swift中想要打印对象要以下重写属性
    override var description: String{
        let keys = ["id","chs","png","imagePath","code","emoticonStr"]
        let dic = dictionaryWithValues(forKeys: keys)
        return "\(dic)"

    }


}




class EmoticonAttachment:NSTextAttachment{


    /// 保存当前附件对应的字符串
    var chs: String?
    
    
    
    
    
    
    
    /// 根据表情模型生成表情字符串
//    class func emoticonString(emoticon: KeyboardEmoticon, font: UIFont) -> NSAttributedString {
//        // 1.创建一个附件
//        let attachment = KeyboardEmoticonAttachment()
//        attachment.image = UIImage(contentsOfFile: emoticon.imagePath ?? "")
//        attachment.chs = emoticon.chs
//        
//        // 获取文字的高度
//        let height = font.lineHeight
//        attachment.bounds = CGRect(x: 0, y: -4, width: height, height: height)
//        
//        // 2.根据附件创建一个属性字符串
//        return NSAttributedString(attachment: attachment)
//    }


}



class EmoticonTextView: UITextView {

    func insertEmoticon(emotion: EmoticonFace) {

        //判断是否是删除按钮
        if emotion.isRemoveButton {

            deleteBackward()


            return
        }


        // 判断是否是emoji表情
        if let temp = emotion.emoticonStr ,temp != "\0"{
            // 1.1获取当前光标所在的位置
            let selectRange = selectedTextRange!
            // 1.2利用表情字符串替换光标所在位置
            replace(selectRange, withText: temp)

            return

        }



        // 判断是否是图片表情
        if let path = emotion.imagePath {
            // 0.根据现在显示的内容生成一个属性字符串


            let strM = NSMutableAttributedString(attributedString: (attributedText)!)
            
            // 1.创建一个附件
            let attachment = EmoticonAttachment()
            attachment.image = UIImage(contentsOfFile: path)
            attachment.chs = emotion.chs
            // 获取文字的高度
            
            let height = font!.lineHeight
            attachment.bounds = CGRect(x: 0, y: -4, width: height, height: height)
            
            // 2.根据附件创建一个属性字符串
            let attrStr = NSAttributedString(attachment: attachment)
            
            // 3.将输入字符串插入到光标所在的位置
            let range = selectedRange
            strM.replaceCharacters(in: range, with: attrStr)
            
            // 123[哈哈]456
            
            // 4.重新设置插入表情的文字大小
            strM.addAttribute(NSFontAttributeName, value: font!, range: NSMakeRange(range.location, 1))
            
            // 4.设置textView为属性字符串
            attributedText = strM
            
            // 5.还原光标所在的位置
            selectedRange = NSMakeRange(range.location + 1, 0)
            return
        }
        
        
        
    }




    func getEmoticonString() -> String {

        // 获取发送给服务器的字符串, 需要将图片表情替换为该表情对应的字符串
        // 123😘456
        // 123[爱你]456

        // 1.遍历textView上的内容

        var strM = ""

       attributedText.enumerateAttributes(in: NSMakeRange(0, attributedText.length), options: NSAttributedString.EnumerationOptions(rawValue: 0)) { (dict, range, _) -> Void in

            /*
             如果是纯字符串, 那么返回的就是该字符串的范围
             如果字符串中包含了`图片`表情,那么返回的就是每一段的范围(纯文本算一段/图片表情算一段)
             */
            //            print(range)

            /*
             如果是纯字符串, 那么返回一个字典, 字典的key是以NSFont开头
             如果字符串中包含了`图片`表情,那么返回的就是一段一段的范围, (纯字符串算一个字典, 图片表情算一个字典)纯文本中字典以NSFont开头, 图片表情中字典以NSAttachment开头

             换句话来说, 就是如果是图片表情, 那么返回的字典中就有NSAttachment这个key, 如果是文本或者emoji表情, 就没有NSAttachment
             */

            // <NSTextAttachment: 0x7fc990478720>
            // <NSTextAttachment: 0x7fc990478720>
            //            print(dict)


            // 判断是否是图片表情
            if dict["NSAttachment"] != nil {
                //                strM += "[好爱哦]"
                // 1.取出当前出入的附件
                let attachment = dict["NSAttachment"] as! EmoticonAttachment
                strM += attachment.chs ?? ""
            }else {
                let str: NSString = attributedText.string as NSString
                strM += str.substring(with: range)
            }
        }
        
        return strM
        

    }


}
